package com.air.netty.client.protocol;

import com.air.common.util.SpringContextsUtil;
import com.air.common.util.StrUtils;
import com.air.common.util.WxMsgUtil;
import com.air.pojo.AirUserDevice;
import com.air.pojo.ConnectionRecord;
import com.air.service.AirDeviceService;
import com.air.service.ConnectionRecordService;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.context.support.WebApplicationContextUtils;

import javax.annotation.Resource;
import javax.servlet.ServletContext;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.lang.reflect.Method;
/**
 * @Description
 * @Author semstouch
 * @Date 2016/12/9
 **/
@Component
@ChannelHandler.Sharable
public class ModbusHandler extends SimpleChannelInboundHandler<Object> {
    protected static final Logger logger = LoggerFactory.getLogger(ModbusHandler.class);

    private ServletContext servletContext;
    @Resource
    private ConnectionRecordService connectionRecordService;
    @Resource
    private AirDeviceService airDeviceService;
    @Autowired
    private SpringContextsUtil springContextsUtil;
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Object obj)
            throws Exception {
        Channel incoming = ctx.channel();
        String incomingIp = "";
        String incomingPort = "";
        if (obj instanceof Modbus) {
            Modbus msg = (Modbus) obj;
            StringBuffer data = new StringBuffer();
            data.append(msg.getHEADER_BEGIN());
            data.append(msg.getUID());
            data.append(msg.getHEADER_END());
            data.append(msg.getCODE());
            data.append(msg.getLEN());
            data.append(msg.getDATA());

            //CRC校验
            if (StrUtils.checkCRC(data.toString(), msg.getCRC())) {
                String agreement = msg.getHEADER_BEGIN()
                        + msg.getUID()
                        + msg.getHEADER_END()
                        + msg.getCODE() + msg.getLEN()
                        + msg.getDATA() + msg.getCRC()
                        + msg.getFOOTER();

                String address = incoming.remoteAddress().toString();
                String regex = "/(.*?):(.*)";
                Pattern p = Pattern.compile(regex);
                Matcher m = p.matcher(address);
                while (m.find()) {
                    incomingIp = m.group(1);
                    incomingPort = m.group(2);
                }

                Method method = ReflectionUtils.findMethod(springContextsUtil.getBean(msg.getCODE()).getClass(),"init", Modbus.class, Channel.class, ServletContext.class);
                Object[] param1 = new Object[3];
                param1[0]=msg;
                param1[1]=incoming;
                param1[2]=servletContext;
                ReflectionUtils.invokeMethod(method, springContextsUtil.getBean(msg.getCODE()), param1);

                ConnectionRecord connectionRecord = new ConnectionRecord();
                connectionRecord.setRecord_ip(incomingIp);
                connectionRecord.setRecord_port(incomingPort);
                connectionRecord.setRecord_agreement(agreement);
                connectionRecordService.saveRecord(connectionRecord);

            }
        }
    }

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {  // (2)
        Channel incoming = ctx.channel();
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {  // (3)
        Channel incoming = ctx.channel();
        String ip = incoming.remoteAddress().toString();
        logger.info("设备连接断开····");
        Map<String, String> ipUIDMap = (Map<String, String>) servletContext.getAttribute("ipUIDMap");
        Map<String, Channel> clientMap = (Map<String, Channel>) servletContext.getAttribute("clientMap");


        if (ipUIDMap != null) {
            String UID = ipUIDMap.get(ip).toString();
            logger.info("设备" + UID + "连接断开····");
            if (!UID.equals("")) {
                if (clientMap != null) {
                    //清除UID-channel关系
                    clientMap.remove(UID);
                    servletContext.setAttribute("clientMap", clientMap);
                }
                //清除ip-UID关系
                ipUIDMap.remove(ip);
                servletContext.setAttribute("ipUIDMap", ipUIDMap);
                List<AirUserDevice> list = airDeviceService.queryDeviceOpenid(UID);
                logger.info("----查询结果数为：" + list.size());
                if (list != null) {
                    for (AirUserDevice airUserDevice : list) {
                        WxMsgUtil.sendLoginOutMsg(UID,servletContext,airUserDevice.getOpenid());
                    }
                }
                logger.info("设备" + UID + "连接断开成功");
            }
        }


    }


    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ctx.flush();
    }
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt)
            throws Exception {
        // TODO Auto-generated method stub
        super.userEventTriggered(ctx, evt);

        if (evt instanceof IdleStateEvent) {

            IdleStateEvent event = (IdleStateEvent) evt;

            if (event.state().equals(IdleState.READER_IDLE)) {
                //未进行读操作
                logger.info("客户端心跳超时");
                // 超时关闭channel
                ctx.close();

            }
            logger.info("异常事件"+event.state().toString());

        }
    }
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        logger.info("捕获异常");
        super.channelInactive(ctx);
    }



    public ServletContext getServletContext() {
        return servletContext;
    }

    public void setServletContext(ServletContext servletContext) {
        this.servletContext = servletContext;
    }
}
